"""
pyttsx3离线语音合成引擎实现
"""

import asyncio
import io
import tempfile
import wave
from typing import Dict, List, Optional, Any
import pyttsx3
import soundfile as sf
import numpy as np

from .base import TTSEngine, TTSRequest, TTSResponse, VoiceProfile, TTSException, SynthesisError


class Pyttsx3Engine(TTSEngine):
    """pyttsx3语音合成引擎"""
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        super().__init__(config)
        self._engine = None
        self._current_voice_id = None
        self._lock = asyncio.Lock()
    
    async def initialize(self) -> bool:
        """初始化pyttsx3引擎"""
        try:
            # 在事件循环中运行同步初始化
            loop = asyncio.get_event_loop()
            self._engine = await loop.run_in_executor(
                None, pyttsx3.init
            )
            
            # 设置默认参数
            if self._engine:
                self._engine.setProperty('rate', 200)
                self._engine.setProperty('volume', 0.9)
                
                # 获取可用语音
                await self._load_available_voices()
                return True
            return False
        except Exception as e:
            raise TTSException(f"Failed to initialize pyttsx3 engine: {str(e)}")
    
    async def _load_available_voices(self):
        """加载可用语音列表"""
        if not self._engine:
            return
        
        try:
            loop = asyncio.get_event_loop()
            voices = await loop.run_in_executor(
                None, self._engine.getProperty, 'voices'
            )
            
            self._available_voices = []
            for i, voice in enumerate(voices):
                language_code = voice.languages[0] if voice.languages else "en"
                gender = self._extract_gender(voice.name or "")
                voice_id = f"{language_code}-{gender}-{i+1}"
                voice_profile = VoiceProfile(
                    id=voice_id,
                    name=voice.name or f"Voice {i}",
                    language=language_code,
                    gender=gender,
                    age="adult",
                    accent=voice.id,
                    engine="pyttsx3",
                    settings={
                        "voice_id": voice.id,
                        "name": voice.name,
                        "languages": voice.languages
                    }
                )
                self._available_voices.append(voice_profile)
        except Exception as e:
            print(f"Error loading voices: {e}")
    
    def _extract_gender(self, voice_name: str) -> str:
        """从语音名称提取性别信息"""
        voice_name_lower = voice_name.lower()
        if any(keyword in voice_name_lower for keyword in ['female', 'woman', 'girl']):
            return "female"
        elif any(keyword in voice_name_lower for keyword in ['male', 'man', 'boy']):
            return "male"
        else:
            return "neutral"
    
    async def get_available_voices(self) -> List[VoiceProfile]:
        """获取可用的语音列表"""
        return self._available_voices.copy()
    
    async def set_voice_profile(self, voice_profile: VoiceProfile) -> bool:
        """设置语音配置"""
        if not self._engine:
            return False
        
        try:
            # 查找匹配的语音
            target_voice = None
            for voice in self._available_voices:
                if (voice.id == voice_profile.id or 
                    voice.name == voice_profile.name):
                    target_voice = voice
                    break
            
            if not target_voice:
                return False
            
            loop = asyncio.get_event_loop()
            await loop.run_in_executor(
                None, 
                lambda: self._engine.setProperty('voice', target_voice.settings['voice_id'])
            )
            self._current_voice_id = target_voice.id
            return True
        except Exception as e:
            print(f"Error setting voice profile: {e}")
            return False
    
    async def synthesize(self, request: TTSRequest) -> TTSResponse:
        """语音合成"""
        if not self.validate_request(request):
            return self.create_error_response("Invalid request parameters")
        
        if not self._engine:
            return self.create_error_response("Engine not initialized")
        
        async with self._lock:
            try:
                # 设置语音参数
                if request.voice_profile:
                    await self.set_voice_profile(request.voice_profile)
                
                # 设置语速和音量
                loop = asyncio.get_event_loop()
                await loop.run_in_executor(
                    None, lambda: self._engine.setProperty('rate', request.rate)
                )
                await loop.run_in_executor(
                    None, lambda: self._engine.setProperty('volume', request.volume)
                )
                
                # 生成音频数据
                audio_data, duration = await self._synthesize_to_bytes(request.text)
                
                # 转换格式
                format_value = request.format.value if hasattr(request.format, 'value') else request.format
                if format_value != "wav":
                    audio_data = await self._convert_audio_format(
                        audio_data, format_value, request.sample_rate
                    )
                
                # 保存到文件（如果指定了路径）
                if request.output_path:
                    await self._save_audio_file(audio_data, request.output_path)
                
                # 确保格式值有效
                format_value = request.format.value if hasattr(request.format, 'value') else request.format
                
                return TTSResponse(
                    success=True,
                    audio_data=audio_data,
                    audio_path=request.output_path,
                    duration=duration,
                    metadata={
                        "engine": "pyttsx3",
                        "format": format_value,
                        "sample_rate": request.sample_rate,
                        "text_length": len(request.text)
                    }
                )
            except Exception as e:
                return self.create_error_response(f"Synthesis failed: {str(e)}")
    
    async def _synthesize_to_bytes(self, text: str) -> tuple[bytes, float]:
        """将文本合成为音频字节"""
        # 创建输出文件
        output_file = "temp_output.wav"
        
        try:
            # 设置保存回调
            self._engine.save_to_file(text, output_file)
            
            # 运行合成（在事件循环中运行同步代码）
            loop = asyncio.get_event_loop()
            await loop.run_in_executor(None, self._engine.runAndWait)
            
            # 读取音频文件
            with open(output_file, 'rb') as f:
                audio_data_bytes = f.read()
            
            # 使用wave模块解析WAV文件获取时长
            with io.BytesIO(audio_data_bytes) as wav_io:
                with wave.open(wav_io, 'rb') as wav_file:
                    frames = wav_file.getnframes()
                    rate = wav_file.getframerate()
                    duration = frames / float(rate)
            
            return audio_data_bytes, duration
        finally:
            # 清理文件
            import os
            if os.path.exists(output_file):
                os.unlink(output_file)
    
    async def _convert_audio_format(self, audio_data: bytes, target_format, sample_rate: int) -> bytes:
        """转换音频格式"""
        try:
            # 读取音频数据
            with io.BytesIO(audio_data) as temp_input:
                audio_data_array, _ = sf.read(temp_input)
            
            # 转换格式
            with io.BytesIO() as temp_output:
                # 如果target_format是字符串，则直接使用；如果是枚举，则使用.value
                format_str = target_format if isinstance(target_format, str) else target_format.value
                sf.write(temp_output, audio_data_array, sample_rate, format=format_str)
                return temp_output.getvalue()
        except Exception as e:
            raise SynthesisError(f"Audio format conversion failed: {str(e)}")
    
    async def _save_audio_file(self, audio_data: bytes, file_path: str):
        """保存音频文件"""
        try:
            with open(file_path, 'wb') as f:
                f.write(audio_data)
        except Exception as e:
            raise SynthesisError(f"Failed to save audio file: {str(e)}")
    
    async def cleanup(self):
        """清理资源"""
        if self._engine:
            try:
                loop = asyncio.get_event_loop()
                await loop.run_in_executor(None, self._engine.stop)
            except Exception as e:
                print(f"Error during cleanup: {e}")
            finally:
                self._engine = None
                self._available_voices.clear()
